package thread;

// 第一种创建线程的方法
class MyThread extends Thread{ // 继承标准库Thread类

    public void run(){ // 重写run方法
        // 改进之后：
        while (true){
            System.out.println("hello thread");

            // 为了打印慢一点，方便看，加一个sleep  休眠一秒(需要抛异常)
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        // 改进之前：
      //  System.out.println("hello world");
    }
}

public class ThreadDemo1 {
    public static void main(String[] args) {
        //Thread thread = new Thread(); //Thread 这个类并不需要引入import 任何包
        Thread thread = new MyThread();
        // 因为它在java.long下面
        // String、StringBuilder、StringBuffer 等这几个都是独立导入的

        // 而创建线程是希望线程成为一个独立的执行流（执行一段代码）
        // 怎么创建？有很中写法
        thread.start(); // start() 是属于线程中的特殊方法
        // 效果就是启动一个线程 : 到这里运行结果是"hello world"

        // start 是创建了一个线程，而是由新的线程来执行thread.run方法
        // 这个就是调用了操作系统的API 通过操作系统内核创建新的线程的PCB，并且把要执行的指令交给这个PCB
        // 当PCB被调度到了CPU上执行的时候，也就执行到了线程run的方法中的代码了。

        // 还有就是如果直接调用run的时候那就只是打印 hello thread了，编程单线程了

        // 如果只是直接打印"hello world"，你的java进程主要就是一个线程。（调用main方法的线程），主线程
        // 而通过thread.start()则是，主线程调用了thread.start()，创建出一个新线程，新线程调用thread.run()
        // 如果run方法执行完毕，新的线程就会自然销毁


        // 那么好了 ， 接下来通过改进代码来深刻的体会到并发编程
        // 改进
        // 增加一个while循环
        while(true){
            System.out.println("hello main");
            // 为了打印慢一点，方便看，加一个sleep  休眠一秒(需要抛异常)
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //  通过运行就会发现 是交替打印 hello thread 和 hello main
        // 而不是跟之前想的while不结束就不会执行下面的while语句
        // 这里是并发执行的（并没有出现只打印一个而不打印另一个）

        // 但是运行后不一定谁先谁后，因为操作系统调度线程的时候，是“抢占式执行”，具体哪个线程先上哪个线程先后，不确定
        // 取决于操作系统调度器具体实现策略，
        // 虽然有优先级 ， 但是在应用程序层面上无法修改。 从应用程序（代码）角度，看到的效果，就好像是 线程之间的调度顺序是“随机的”
        // 内核并非是随机的，但是干预的因素太多了，并且应用程序这一层也是无法感知到的细节，就只能认为是随机的了
        // （但是可以用一些api进行有限度的干预）


        // 而start 和 run 之间的区别
        // start是真正创建了一个线程（从系统那里创建），线程是独立执行流
        // run 只是描述了线程要干的活是啥。如果直接再 main 中调用 run，此时没有创建新线程，全是main 线程一个人干活
        // （一个人干活就很有可能干不过来）


        // 这一共是两个线程 main一个线程 start是一个线程
        // start是创建一个线程

        // 可以使用jdk自带的工具jconsole文件查看当前的java进程中所有的线程


        // ****然而再java中创建线程的方式有很多中****
        // 1. 继承Thread ， 重写run方法
        // 2. 实现Runnable 接口
        // 3.使用匿名内部类，继承Thread
        // 4.使用匿名内部类，实现Runnable接口
        // 5. 使用Lambda表达式
    }
}
